using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using SDMX_ML.Framework.Interfaces;
using SDMX_Common = SDMX_ML.Framework.Common;
using SDMX_Message = SDMX_ML.Framework.Message;
using SDMX_Messages = SDMX_ML.Framework.Messages;

namespace SDMX_ML.Framework.Message
{
    /// <summary>
    /// Headertype to be used in any message.
    /// </summary>
    public class HeaderType
    {
        

        private XNamespace _nsQueryMessage;
        private XNamespace _nsQuery;
        private XNamespace _default;
        private XElement _xml;

        private PartyType _sender;
        private PartyType _receiver;
        private string _id;
        private bool? _test;
        private bool? _truncated;
        private string  _name;
        private SDMX_Common.EnumDataSetAction? _datasetaction;
        private string _extracted;
        private string _prepared;
        private string _datasetagency;
        private string _datasetid;
        private string _keyFamilyRef;
        private string _keyFamilyAgency;
        private string _reportBegin;
        private string _reportEnd;
        private SDMX_Common.TextType _source;
   

        public HeaderType(){}

        public HeaderType(XElement header)
        {
            _xml = header;
            SetXMLHeader();
        }

        #region Properties

        public SDMX_Common.TextType Source
        {
            get { return _source; }
            set { _source = value; }
        }

        public string ReportEnd
        {
            get { return _reportEnd; }
            set { _reportEnd = value; }
        }

        public string ReportBegin
        {
            get { return _reportBegin; }
            set { _reportBegin = value; }
        }

        public string KeyFamilyRef
        {
            get { return _keyFamilyRef; }
            set { _keyFamilyRef = value; }
        }

        public string KeyFamilyAgency
        {
            get { return _keyFamilyAgency; }
            set { _keyFamilyAgency = value; }
        }

        public PartyType Sender
        {
            get { return _sender; }
            set { _sender = value; }
        }

        public PartyType Receiver
        {
            get { return _receiver; }
            set { _receiver = value; }
        }

        public string Id
        {
            get { return _id; }
            set { _id = value; }
        }

        public bool? Test
        {
            get { return _test; }
            set { _test = value; }
        }

        public bool? Truncated
        {
            get { return _truncated; }
            set { _truncated = value; }
        }

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public string Prepared
        {
            get { return _prepared; }
            set { _prepared = value; }
        }

        public string DataSetAgency
        {
            get { return _datasetagency; }
            set { _datasetagency = value; }
        }

        public string DataSetID
        {
            get { return _datasetid; }
            set { _datasetid = value; }
        }

        public SDMX_Common.EnumDataSetAction? DataSetAction
        {
            get { return _datasetaction; }
            set { _datasetaction = value; }
        }

        public string Extracted
        {
            get { return _extracted; }
            set { _extracted = value; }
        }

        #endregion

        #region WriteXML

        public string ToXml()
        {
            XElement header = GetXml();

            return header.ToString();
        }

        public XElement GetXml()
        {
            XElement header = new XElement(Namespaces.GetNS("message") + "Header");
            
            if(_id != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "ID", _id));
            }

            if (_test != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "Test", _test.ToString().ToLower()));
            }

            if (_truncated != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "Truncated", _truncated.ToString().ToLower()));
            }

            if (_name != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "Name", _name, new XAttribute(XNamespace.Xml + "lang", "en")));
            }

            if (_prepared != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "Prepared", _prepared));
            }

            if (_sender != null)
            {
                XElement sender = new XElement(Namespaces.GetNS("message") + "Sender");

                if (!String.IsNullOrEmpty(_sender.Id))
                {
                    sender.Add(new XAttribute("id", _sender.Id));
                }

                if (_sender.Name.Count > 0)
                {
                    foreach(SDMX_Common.TextType name in _sender.Name)
                    {
                        sender.Add(SDMX_Messages.ElementBuilder.GetTextType(name, "Name", Namespaces.GetNS("message")));
                    }
                }

                header.Add(GetContact(sender, _sender.Contact));
            }

            if (_receiver != null)
            {
                XElement receiver = new XElement(Namespaces.GetNS("message") + "Receiver");

                if (_receiver.Id != null)
                {
                    receiver.Add(new XAttribute("id", _receiver.Id));
                }

                if (_receiver.Name.Count > 0)
                {
                    foreach(SDMX_Common.TextType name in _receiver.Name)
                    {
                        receiver.Add(SDMX_Messages.ElementBuilder.GetTextType(name, "Name", Namespaces.GetNS("message")));
                    }

                }

                header.Add(GetContact(receiver, _receiver.Contact));
            }

            if (_keyFamilyRef != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "KeyFamilyRef", _keyFamilyRef));
            }

            if (_keyFamilyAgency != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "KeyFamilyAgency", _keyFamilyAgency));
            }

            if (_datasetagency != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "DataSetAgency", _datasetagency));
            }

            if (_datasetid != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "DataSetID", _datasetid));
            }

            if (_datasetaction != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "DataSetAction", _datasetaction.ToString()));
            }

            if (_extracted != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "Extracted", _extracted));
            }

            if (_reportBegin != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "ReportingBegin", _reportBegin));
            }

            if (_reportEnd != null)
            {
                header.Add(new XElement(Namespaces.GetNS("message") + "ReportingEnd", _reportEnd));
            }

            if (_source != null)
            {
                header.Add(SDMX_Messages.ElementBuilder.GetTextType(_source, "Source", Namespaces.GetNS("message")));
            }
             
            

            return header;

        }

        
        private XElement GetContact(XElement sr, List<ContactType> contacts)
        {
 
            foreach(ContactType c in contacts)
            {
                XElement contact = 
                    new XElement(Namespaces.GetNS("message") + "Contact");
                
                if(c.Name.Count > 0)
                {
                    foreach (SDMX_Common.TextType name in c.Name)
                    {
                        contact.Add(SDMX_Messages.ElementBuilder.GetTextType(name, "Name", Namespaces.GetNS("message")));
                    }
                }

                if(c.Department.Count > 0)
                {
                    foreach (SDMX_Common.TextType department in c.Department)
                    {
                        contact.Add(SDMX_Messages.ElementBuilder.GetTextType(department, "Department", Namespaces.GetNS("message")));
                    }
                }

                if (c.Role.Count > 0)
                {
                    foreach (SDMX_Common.TextType role in c.Role)
                    {
                        contact.Add(SDMX_Messages.ElementBuilder.GetTextType(role, "Role", Namespaces.GetNS("message")));
                    }
                }

                if (c.Telephone.Count > 0)
                {
                    foreach (string telephone in c.Telephone)
                    {
                        contact.Add(new XElement(Namespaces.GetNS("message") + "Telephone", telephone));
                    }
                }

                if (c.Fax.Count > 0)
                {
                    foreach (string fax in c.Fax)
                    {
                        contact.Add(new XElement(Namespaces.GetNS("message") + "Fax", fax));
                    }
                }

                if (c.X400.Count > 0)
                {
                    foreach (string x400 in c.X400)
                    {
                        contact.Add(new XElement(Namespaces.GetNS("message") + "X400", x400));
                    }
                }

                if (c.Uri.Count > 0)
                {
                    foreach (string uri in c.Uri)
                    {
                        contact.Add(new XElement(Namespaces.GetNS("message") + "Uri", uri));
                    }
                }

                if (c.Email.Count > 0)
                {
                    foreach (string email in c.Email)
                    {
                        contact.Add(new XElement(Namespaces.GetNS("message") + "Email", email));
                    }
                }

               

                sr.Add(contact);
            }

            return sr;
        }

        #endregion

        #region CreateHeader

        private void SetXMLHeader()
        {
 
            _default = Namespaces.GetNS("message");

            //XElement header = _xml.Element(_default + "Header");

            if (_xml.Element(_default + "ID") != null)
            {
                _id = _xml.Element(_default + "ID").Value;
            }

            if (_xml.Element(_default + "Test") != null)
            {
                _test = Convert.ToBoolean(_xml.Element(_default + "Test").Value);
            }

            if (_xml.Element(_default + "Truncated") != null)
            {
                _truncated = Convert.ToBoolean(_xml.Element(_default + "Truncated").Value);
            }

            if (_xml.Element(_default + "Name") != null)
            {
                _name = _xml.Element(_default + "Name").Value;
            }

            if (_xml.Element(_default + "Prepared") != null)
            {
                _prepared = _xml.Element(_default + "Prepared").Value;
            }

            if (_xml.Element(_default + "Sender") != null)
            {
                _sender = GetParty(_xml.Element(_default + "Sender"));
            }

            if (_xml.Element(_default + "Receiver") != null)
            {
                _receiver = GetParty(_xml.Element(_default + "Receiver"));
            }

            if (_xml.Element(_default + "KeyFamilyRef") != null)
            {
                if (_xml.Element(_default + "KeyFamilyRef").Value != null)
                {
                    _keyFamilyRef = _xml.Element(_default + "KeyFamilyRef").Value;
                }
            }

            if (_xml.Element(_default + "KeyFamilyAgency") != null)
            {
                if (_xml.Element(_default + "KeyFamilyAgency").Value != null)
                {
                    _keyFamilyRef = _xml.Element(_default + "KeyFamilyAgency").Value;
                }
            }

            if (_xml.Element(_default + "DataSetAgency") != null)
            {
                if (_xml.Element(_default + "DataSetAgency").Value != null)
                {
                    _datasetagency = _xml.Element(_default + "DataSetAgency").Value;
                }
            }

            if (_xml.Element(_default + "DataSetID") != null)
            {
                if (_xml.Element(_default + "DataSetID").Value != null)
                {
                    _datasetid = _xml.Element(_default + "DataSetID").Value;
                }
            }

            if (_xml.Element(_default + "DataSetAction") != null)
            {
                if (_xml.Element(_default + "DataSetAction").Value != null)
                {
                    _datasetaction = SDMX_Common.EnumerationConvert.EnumDataSetActionFromString(_xml.Element(_default + "DataSetAction").Value);
                }
            }

            if (_xml.Element(_default + "Extracted") != null)
            {
                if (_xml.Element(_default + "Extracted").Value != null)
                {
                    _extracted = _xml.Element(_default + "Extracted").Value;
                }
            }

            if (_xml.Element(_default + "ReportingBegin") != null)
            {
                if (_xml.Element(_default + "ReportingBegin").Value != null)
                {
                    _reportBegin = _xml.Element(_default + "ReportingBegin").Value;
                }
            }

            if (_xml.Element(_default + "ReportingEnd") != null)
            {
                if (_xml.Element(_default + "ReportingEnd").Value != null)
                {
                    _reportEnd = _xml.Element(_default + "ReportingEnd").Value;
                }
            }

            if (_xml.Element(_default + "Source") != null)
            {
                if (_xml.Element(_default + "Source").Value != null)
                {
                    _source = SDMX_Messages.ObjectBuilder.GetTextType(_xml.Element(_default + "Source"));
                }
            }
        }

        private SDMX_Message.PartyType GetParty(XElement party)
        {
            SDMX_Message.PartyType element = null;

            if (party.Attribute("id") != null)
            {
                if (party.Attribute("id").Value != null)
                {
                    element = new PartyType(party.Attribute("id").Value);
                }
                else
                {
                    element = new PartyType("ID value is missing!!!");
                }
            }

            if(party.Element(_default + "Name") != null)
            {
                foreach (XElement name in party.Elements(_default + "Name"))
                {
                    element.Name.Add(SDMX_Messages.ObjectBuilder.GetTextType(name));
                }
            }

            foreach (XElement c in party.Elements(_default + "Contact"))
            {
                element.Contact.Add(GetContact(c));
            }

            return element;

        }

        private SDMX_Message.ContactType GetContact(XElement contact)
        {
            SDMX_Message.ContactType con = new SDMX_Message.ContactType();

            //XElement name = contact.Element(_default + "Name");

            if (contact.Element(_default + "Name") != null)
            {
                foreach (XElement contactName in contact.Elements(_default + "Name"))
                {
                    con.Name.Add(SDMX_Messages.ObjectBuilder.GetTextType(contactName));
                }
            }

            if (contact.Element(_default + "Department") != null)
            {
                foreach (XElement contactDepartment in contact.Elements(_default + "Department"))
                {
                    con.Department.Add(SDMX_Messages.ObjectBuilder.GetTextType(contactDepartment));
                }
            }

            if (contact.Element(_default + "Role") != null)
            {
                foreach (XElement contactRole in contact.Elements(_default + "Role"))
                {
                    con.Role.Add(SDMX_Messages.ObjectBuilder.GetTextType(contactRole));
                }
            }

            if (contact.Element(_default + "Telephone") != null)
            {
                foreach (XElement contactTelephone in contact.Elements(_default + "Telephone"))
                {
                    if (!String.IsNullOrEmpty(contactTelephone.Value))
                    {
                        con.Telephone.Add(contactTelephone.Value);
                    }
                }
            }

            if (contact.Element(_default + "Fax") != null)
            {
                foreach (XElement contactFax in contact.Elements(_default + "Fax"))
                {
                    if (!String.IsNullOrEmpty(contactFax.Value))
                    {
                        con.Fax.Add(contactFax.Value);
                    }
                }
            }

            if (contact.Element(_default + "X400") != null)
            {
                foreach (XElement contactX400 in contact.Elements(_default + "X400"))
                {
                    if (!String.IsNullOrEmpty(contactX400.Value))
                    {
                        con.X400.Add(contactX400.Value);
                    }
                }
            }

            if (contact.Element(_default + "URI") != null)
            {
                foreach (XElement contactURI in contact.Elements(_default + "URI"))
                {
                    if (!String.IsNullOrEmpty(contactURI.Value))
                    {
                        con.Uri.Add(contactURI.Value);
                    }
                }
            }

            if (contact.Element(_default + "Email") != null)
            {
                foreach (XElement contactEmail in contact.Elements(_default + "Email"))
                {
                    if (!String.IsNullOrEmpty(contactEmail.Value))
                    {
                        con.Email.Add(contactEmail.Value);
                    }
                }
            }

            return con;
        }

        #endregion
    }
}
